#!/usr/bin/python
# -*- coding: utf-8 -*-

import pygst
pygst.require("0.10")
import gst
import gobject

import threading
from signal import *
import time

# RPC-JSON
import utils.jsonrpc as jsonrpc
from os import path, unlink


IP_VIDEOSERVER = "127.0.0.1"
LOCALHOST = "127.0.0.1" # don't work when write "localhost"
ROOT_DIR = path.dirname(__file__)
UNIXSOCKET = path.join(ROOT_DIR,"socketipc")

#RTP_RECV_PORT = 5000
#RTCP_RECV_PORT = 5001
#RTCP_SEND_PORT = 5005

gobject.threads_init()
        
        
class ChannelManager:
    def __init__(self, channelID):
        def bus_handler(unused_bus, message):
            if message.type == gst.MESSAGE_ERROR:
                print message
            return gst.BUS_PASS
        
        self.channelID = channelID

        if self.channelID == 1:
            print "oui"
            self.RTP_RECV_PORT = 5000
            self.RTCP_RECV_PORT = 5001
            self.RTCP_SEND_PORT = 5005
            self.pipeline = gst.Pipeline("Channela")
        else:
            self.RTP_RECV_PORT = 6000
            self.RTCP_RECV_PORT = 6001
            self.RTCP_SEND_PORT = 6005       
            self.pipeline = gst.Pipeline("Channelb")
            

        print self.channelID
        # Create a Pipeline
        #self.pipeline = gst.Pipeline("Channel%d" % self.channelID)

        
        #Connect to the bus to get the messages
        self.bus = self.pipeline.get_bus()
        self.bus.add_signal_watch()
        self.bus.connect("message", bus_handler)
        
        # the udp src and source we will use for self.RTP and self.RTCP
        self.rtpsrc = gst.element_factory_make('udpsrc', 'rtpsrc')
        self.rtpsrc.set_property('port', self.RTP_RECV_PORT)

        # we need to set caps on the udpsrc for the self.RTP data
        self.caps = gst.caps_from_string("application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H263-1998")
        self.rtpsrc.set_property('caps', self.caps)
        
        self.rtcpsrc = gst.element_factory_make('udpsrc', 'rtcpsrc')
        self.rtcpsrc.set_property('port', self.RTCP_RECV_PORT)

        self.rtcpsink = gst.element_factory_make('udpsink', 'rtcpsink')
        self.rtcpsink.set_property('port', self.RTCP_SEND_PORT)
        self.rtcpsink.set_property('host', IP_VIDEOSERVER)
        
        # no need for synchronisation or preroll on the self.RTCP sink
        self.rtcpsink.set_property('async', False)
        self.rtcpsink.set_property('sync', False) 
        

        self.pipeline.add(self.rtpsrc, self.rtcpsrc, self.rtcpsink)
        
        # the depayloading and decoding
        self.videodepay = gst.element_factory_make("rtph263pdepay", 'videodepay')
        self.videodec = gst.element_factory_make("ffdec_h263", 'videodec')

        #Video Sink
        self.colorspace = gst.element_factory_make("ffmpegcolorspace", "colorspace")
        #self.sink = cluttergst.VideoSink(self.video_texture) # Attaches the output texture to gstreamer sink
        
        
        # the rtpbin element
        self.rtpbin = gst.element_factory_make('gstrtpbin', 'rtpbin') 
        self.pipeline.add(self.rtpbin)
        
        
        # now link all to the rtpbin, start by getting an self.RTP sinkpad for session 0
        self.srcpad = gst.Element.get_static_pad(self.rtpsrc, 'src')
        self.sinkpad = gst.Element.get_request_pad(self.rtpbin, 'recv_rtp_sink_0')
        lres = gst.Pad.link(self.srcpad, self.sinkpad)

        # get an RTCP sinkpad in session 0
        self.srcpad = gst.Element.get_static_pad(self.rtcpsrc, 'src')
        self.sinkpad = gst.Element.get_request_pad(self.rtpbin, 'recv_rtcp_sink_0')
        lres = gst.Pad.link(self.srcpad, self.sinkpad)

        # get an RTCP srcpad for sending RTCP back to the sender
        self.srcpad = gst.Element.get_request_pad(self.rtpbin, 'send_rtcp_src_0')
        self.sinkpad = gst.Element.get_static_pad(self.rtcpsink, 'sink')
        lres = gst.Pad.link(self.srcpad, self.sinkpad)

        self.rtpbin.connect('pad-added', self.pad_added_cb) 
        self.rtpbin.connect('pad-removed', self.pad_removed_cb) 
        
        
        gst.Element.set_state(self.pipeline, gst.STATE_NULL)
        self.pipeline.set_state(gst.STATE_NULL)
        
        
        ## Add server
        self.rtpbinOut = gst.element_factory_make("gstrtpbin", "rtpbinout")
        
        self.vqueue = gst.element_factory_make("queue", "Vbuffer")

        self.udpsinkRTP = gst.element_factory_make("multiudpsink", "udpsinkRTP")
        self.udpsinkRTCP = gst.element_factory_make("multiudpsink", "udpsinkRTCP")
        
        self.udpsinkRTCP.set_property("async", False)
        self.udpsinkRTCP.set_property("sync", False)
        
        self.pipeline.add(self.vqueue, self.udpsinkRTP, self.udpsinkRTCP, self.rtpbinOut)
        
        self.vqueue.link_pads("src", self.rtpbinOut, "send_rtp_sink_3")
        self.rtpbinOut.link_pads("send_rtp_src_3", self.udpsinkRTP, "sink")
        self.rtpbinOut.link_pads("send_rtcp_src_3", self.udpsinkRTCP, "sink") 
        
        self.udpsinkRTP.connect('client-added', self.client_added)
        self.udpsinkRTP.connect('client-removed', self.client_removed)
        ## Fin Server
        
    def addWatcher(self, dest, port):
        print "Add watcher"
        PORT = int(port)
        RTCPPORT = PORT + 1
        self.udpsinkRTP.emit("add", dest, PORT)
        self.udpsinkRTCP.emit("add", dest, RTCPPORT)
        return False # Return false so gobject.idle_add won't call several times the same
        
    def removeWatcher(self, dest, port):
        print "Remove watcher"
        PORT = int(port)
        RTCPPORT = PORT + 1
        self.udpsinkRTP.emit("remove", dest, PORT)
        self.udpsinkRTCP.emit("remove", dest, RTCPPORT)
        return False
        
    def getState(self):
        return self.pipeline.get_state()[1]

    def client_added(self, udpsinkRTP, ip, port):
        print "New client: (%s:%d)" % (ip, port)
        if (self.getState() == gst.STATE_NULL):
            self.play()
            
            
    def client_removed(self, udpsinkRTP, ip, port):
        print "Remove client: (%s:%d)" % (ip, port)
        if (self.getState() == gst.STATE_PLAYING) and (not "," in self.udpsinkRTP.get_property("clients") ):
            self.stop()


    def pad_added_cb(self, rtpbin, new_pad):
        print "Pad added in RTPBIN"
        qv_pad = self.vqueue.get_pad("sink")
        if qv_pad.is_linked():
            pad = qv_pad.get_peer()
            pad.unlink( qv_pad )
        new_pad.link(qv_pad)

    def pad_removed_cb(self, rtpbin, new_pad):
        print "removed pad"

    def play(self):
        print "Start playing video"
        gst.Element.set_state(self.pipeline, gst.STATE_PLAYING)
        self.pipeline.set_state(gst.STATE_PLAYING)
        
    def stop(self):
        print "Stop playing video"
        gst.Element.set_state(self.pipeline, gst.STATE_NULL)
        self.pipeline.set_state(gst.STATE_NULL)
        
        
class MainProg:
    def __init__(self):
        self.channel1 = ChannelManager(channelID = 1)
        self.channel2 = ChannelManager(channelID = 2)
        
        self.channel1.addWatcher("127.0.0.1", 8000)
        
        if path.exists(UNIXSOCKET):
            unlink(UNIXSOCKET)
        self.server = jsonrpc.Server(jsonrpc.JsonRpc20(), jsonrpc.TransportUnixSocket(addr=UNIXSOCKET, logfunc=jsonrpc.log_file("logs/myrpc.log")))
        self.server.register_function( self.addWatcher1, name="addwatcher1" )
        self.server.register_function( self.removeWatcher1, name="removewatcher1" )
        self.server.register_function( self.addWatcher2, name="addwatcher2" )
        self.server.register_function( self.removeWatcher2, name="removewatcher2" )

        signal(SIGINT, self.signal_cb)
        signal(SIGTERM, self.signal_cb)
        
    def signal_cb(self, sig, frame):
        self.channel1.stop()
        self.channel2.stop()
        self.mainloop.quit()
        
        
    def addWatcher1(self, ip, port):
        gobject.idle_add( self.channel1.addWatcher, ip, port )
        return True
        
    def removeWatcher1(self, ip, port):
        gobject.idle_add( self.channel1.removeWatcher, ip, port )
        return True
        
    def addWatcher2(self, ip, port):
        gobject.idle_add( self.channel2.addWatcher, ip, port )
        return True
        
    def removeWatcher2(self, ip, port):
        gobject.idle_add( self.channel2.removeWatcher, ip, port )
        return True
        
    def runMainloop(self):
        self.mainloop = gobject.MainLoop()
        self.mainloop.run()
        
    def run(self):
        self.mainloopThread = threading.Thread(target=self.runMainloop)
        self.mainloopThread.deamon = True
        self.mainloopThread.start()
        
        self.server.serve()

main = MainProg().run()
